`timescale 1ns / 1ps
`include "../../include/cpu_defines.sv"
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/06/23 08:33:20
// Design Name: 
// Module Name: MemIssueQueue1
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module MemIssueQueue1
#(
parameter TOTAL_SIZE=`READ_BUFFER_SIZE+`WRITE_BUFFER_SIZE,
parameter TAG_SIZE = TOTAL_SIZE << 1,
parameter WRITE_RETIRE_BUFFER_SIZE=8,
parameter UNCACHE_BUFFER_SIZE=16,
parameter UNCACHE_BUFFER_WIDTH=$clog2(UNCACHE_BUFFER_SIZE),
parameter STORE_BUFFER_SIZE=8,
parameter STORE_BUFFER_WIDTH=$clog2(STORE_BUFFER_SIZE))(
	input logic cpu_clk,
	input logic cpu_rst_n,
	input logic clear,
	input logic branch_fail_clear,
	input logic stall,
	input logic en1,
	input logic en2,
	input logic [5: 0] inst1_rs,
	input logic [5: 0] inst2_rs,
	input logic [5: 0] inst1_rt,
	input logic [5: 0] inst2_rt,
	input logic [5: 0] inst1_rd,
	input logic [5: 0] inst2_rd,
	input logic [`EXC_CODE_BUS] inst1_exccode,
	input logic [`EXC_CODE_BUS] inst2_exccode,
	input logic [`MEMOP_BUS] inst1_memop,
	input logic [`MEMOP_BUS] inst2_memop,
	input logic inst1_rs_ready,
	input logic inst1_rt_ready,
	input logic inst2_rs_ready,
	input logic inst2_rt_ready,
	input logic [31: 0] inst1_src2,
	input logic [31: 0] inst2_src2,
	input logic [5: 0] rob_index1,
	input logic [5: 0] rob_index2,
	input logic retire_en1,
	input logic retire_en2,
	input logic retire_ll1,
	input logic retire_ll2,
	input logic [5: 0] retire_rob_index1,
	input logic [5: 0] retire_rob_index2,
	input logic wb_en1,
	input logic wb_en2,
	input logic wb_en3,
	input logic [5: 0] wb_rd1,
	input logic [5: 0] wb_rd2,
	input logic [5: 0] wb_rd3,
	input logic inst_wb_receive,
	input logic user_mode,

	output logic [5: 0] search1,
	output logic [5: 0] search2,
	output logic [5: 0] search3,
	output logic search4_en,
	output logic [5: 0] search4, // search port share with cp0 issue queue, for lwl, lwr
	input logic [31: 0] data1,
	input logic [31: 0] data2,
	input logic [31: 0] data3,
	input logic [31: 0] data4,

	output logic mem_end,
	output logic [5: 0] mem_rd,
	output logic [5: 0] next_mem_rd,
	output logic [5: 0] mem_rob_index,
	output logic [31: 0] mem_data,
	(* mark_debug="true" *)
	output logic [31: 0] mem_addr,
	output logic dis_mem_stall_req,
	output logic [`EXC_CODE_BUS] mem_exccode,
	output logic vaddr_we,
	output logic [5: 0] vaddr_rob_index,
	output logic entryhi_we,

	input logic data_addr_ok,
	input logic data_data_ok,
	input logic data_waddr_ok,
	input logic data_uncache_ok,
	input logic write_accept,
	input logic data_success,
	input logic enable_miss_back,
	input logic [31: 0] data_rdata,
	input logic [`READ_BUFFER_WIDTH-1: 0] read_queue_index,
	input logic mshr_data_ok,
	input logic [`READ_BUFFER_WIDTH-1: 0] mshr_queue_index,
	input logic [31: 0] mshr_data,
	input logic rdata_tlb_invalid,
	input logic rdata_tlb_refill,
	input logic wdata_tlb_invalid,
	input logic wdata_tlb_refill,
	input logic data_tlb_modify,
	output logic [19: 0] vwtag,
	input logic [19: 0] pwtag,
	input logic [19: 0] prtag,
	input logic data_wuncache,
	input logic data_runcache,
	(* mark_debug="true" *)
	output logic data_req,
	output logic data_abandon_lookup,
	output logic data_clear,
	(* mark_debug="true" *)
	output logic data_write_req,
	output logic enable_miss,
	output logic [`READ_BUFFER_WIDTH-1: 0] out_queue_index,
	output logic [3: 0] data_rwstrb,
	output logic [3: 0] data_wstrb,
	(* mark_debug="true" *)
	output logic [31: 0] data_addr,
	(* mark_debug="true" *)
	output logic [31: 0] data_waddr,
	(* mark_debug="true" *)
	output logic [31: 0] data_wdata,
	output logic [19: 0] data_write_ptag,
	output logic uncache_req,
	output logic uncache_wr,
	output logic [3: 0] uncache_wstrb,
	output logic [31: 0] uncache_addr,
	output logic [`READ_BUFFER_WIDTH-1: 0] uncache_queue_index,
	output logic [31: 0] uncache_data,
	input logic uncache_data_ok
	);

	typedef struct packed{
		// logic en;
		// logic rs_ready;
		// logic rt_ready;
		// logic data_ready;
		logic force_search;
		// logic in_reorder;
		// logic reorderable;
		logic tlb_refill;
		logic tlb_invalid;
		logic is_unsigned;
		logic lwl, lwr;
		// logic direction;
		logic [`EXC_CODE_BUS] exccode;
		logic [1: 0] size;
		logic [$clog2(TAG_SIZE)-1: 0] index;
		logic [3: 0] wstrb;
		logic [5: 0] rs, rt, rd;
		logic [5: 0] rob_index;
		logic [31: 0] offset;
		logic [31: 0] addr;
		logic [31: 0] data;
		logic [19: 0] ptag;
		logic [31: 0] rt_data;
	}ReadBuffer_t;

	typedef struct packed { 
		logic rs_ready, rt_ready, wb_ready, wait_retire, has_retire, in_store, sc, swl, swr, uncache;
		logic tlb_refill, tlb_invalid, tlb_modify;
		logic [`EXC_CODE_BUS] exccode;
		logic [1: 0] size;
		logic [3: 0] wstrb;
		logic [5: 0] rs, rt, rd;
		logic [5: 0] rob_index;
		logic [19: 0] ptag;
		logic [31: 0] offset;
		logic [31: 0] addr;
		logic [31: 0] data;
	} WriteBuffer_t;

	typedef struct packed{
		logic [$clog2(WRITE_RETIRE_BUFFER_SIZE)-1: 0] index;
		logic [29: 0] addr;
		logic [31: 0] data;
		logic [3: 0] wstrb;
	} StoreBuffer_t;

	typedef struct packed {
		logic [`READ_BUFFER_WIDTH-1: 0] queue_index;
		logic [31: 0] addr;
		logic [31: 0] data;
		logic [3: 0] wstrb;
	} UncacheBuffer_t;

	typedef enum { READ_IDLE, READ_BUSY } read_state_t;

	// read
	ReadBuffer_t read_buffer[`READ_BUFFER_SIZE-1: 0];
	logic [`READ_BUFFER_SIZE-1: 0] read_en, read_rs_ready, read_rt_ready, in_reorder, read_uncache, read_data_ready, read_direction, read_addr_ready;
	logic [`READ_BUFFER_SIZE-1: 0] in_reorder_copy;
	logic [`READ_BUFFER_SIZE-1: 0] reorderable;
	logic [`READ_BUFFER_SIZE-1: 0][`WRITE_BUFFER_SIZE-1: 0] wbr_en; // write before read
	logic [`READ_BUFFER_SIZE-1: 0] wbr_read_valid, wbr_read_next_valid;
	logic [`WRITE_BUFFER_SIZE-1: 0] wbr_write_mask;
	logic [`READ_BUFFER_SIZE: 0] read_remain_count;
	logic [`READ_BUFFER_WIDTH-1: 0] read_head, read_indexp1, read_tail;
	logic [`READ_BUFFER_WIDTH-1: 0] read_search_tail; // 用来判断当前指令是否可以进行访存缺失处理
	logic inst1_load, inst2_load, inst1_unsigned, inst2_unsigned, inst1_load_pre, inst2_load_pre;
	logic [1: 0] inst1_memsize, inst2_memsize, read_add_num;
	logic [`READ_BUFFER_SIZE-1: 0] read_ready, read_ready_pre;
	logic read_valid, is_search_read_tail, read_tail_next, out_direction, out_direction_next, data_req_next, search4_en_next, req_next_stage, data_req_before, data_req_out_next, enable_miss_next;
	logic [7: 0] bwr_combine_en1, wr_combine_en1;
	logic [7: 0][`WRITE_BUFFER_WIDTH-1: 0] bwr_combine_index1, wr_combine_index1;
	logic [7: 0][3: 0] bwr_combine_wstrb1, wr_combine_wstrb1;
	logic [7: 0][31: 0] bwr_combine_data1, wr_combine_data1;
	logic [3: 0] wr_combine_en2;
	logic [3: 0][`WRITE_BUFFER_WIDTH-1: 0] wr_combine_index2;
	logic [3: 0][3: 0] wr_combine_wstrb2;
	logic [3: 0][31: 0] wr_combine_data2;
	logic [1: 0] wr_combine_en3;
	logic [1: 0][`WRITE_BUFFER_WIDTH-1: 0] wr_combine_index3;
	logic [1: 0][3: 0] wr_combine_wstrb3;
	logic [1: 0][31: 0] wr_combine_data3;
	logic wr_combine_en;
	logic [`WRITE_BUFFER_WIDTH-1: 0] wr_combine_index;
	logic [3: 0] wr_combine_wstrb;
	logic [31: 0] wr_combine_data;
	logic [`WRITE_BUFFER_WIDTH-1: 0] wr_commit_tail;
	logic [3: 0] wr_wstrb;
	logic read_valid_next;
	logic [3: 0] read_conflict_wstrb;
	logic read_direction_stage2;
	logic req_direct; // 如果发现读请求是不缓存请求或者全部在store_buffer中，则流水线直接流动
	logic read_data_quick_back; // 如果缓存中直接获得或者store_buffer中存在该次读请求的全部数据则认为访存命中
	logic [`READ_BUFFER_WIDTH-1: 0] read_ready_encode, read_index, read_index_next, read_rt_index, req_next_index;
	logic [$clog2(TAG_SIZE)-1: 0] read_global_index, read_global_index_next, read_global_index3;
	logic [31: 0] store_data3, store_offset, read_addr, data_addr_next, store_data4;
	logic [1: 0] read_addr_offset;
	logic [3: 0] read_wstrb, read_wstrb2, read_wstrb3, remain_wstrb, data_rwstrb_next;
	logic [35: 0] snap_outa, snap_outb, snap_outa1, snap_outb1;
	logic [`WRITE_BUFFER_SIZE-1: 0] read_write_buffer_hit;
	logic [`WRITE_BUFFER_SIZE-1: 0][3: 0] read_write_hit_wstrb;
	logic [31: 0] read_combine_data, req_combine_data, mshr_combine_data;
	logic wr_stage2_conflict, wr_stage3_conflict, wr_stage4_conflict, wr_stage5_conflict1, wr_stage5_conflict2;

	// write
	WriteBuffer_t write_buffer[`WRITE_BUFFER_SIZE-1: 0];
	logic [`WRITE_BUFFER_SIZE-1: 0] write_en, write_direction, write_retire_en, next_write_retire_en;
	logic [`WRITE_BUFFER_SIZE-1: 0][$clog2(TAG_SIZE)-1: 0] write_index;
	logic inst1_store, inst2_store, inst1_store_pre, inst2_store_pre;
	logic [1: 0] write_add_num;
	logic [`WRITE_BUFFER_WIDTH: 0] write_remain_count, write_retire_remain_count, next_write_retire_remain_count;
	logic [`WRITE_BUFFER_WIDTH-1: 0] write_head, write_indexp1, write_search_tail;
	logic writeable, write_ready;
	logic [31: 0] write_addr, write_data;
	logic [1: 0] write_addr_offset, write_size;
	logic swl, swr, write_ready_next, write_search_direction;
	logic [`WRITE_BUFFER_WIDTH-1: 0] write_search_tail_next;
	logic [31: 0] fetch_addr, fetch_data;
	logic [1: 0] fetch_offset, fetch_size;
	logic fetch_swl, fetch_swr, fetch_ready, fetch_direction, fetch_uncache;
	logic fetch_tlb_invalid, fetch_tlb_refill, fetch_tlb_modify;
	logic [19: 0] fetch_ptag;
	logic [`WRITE_BUFFER_WIDTH-1: 0] fetch_index;
	logic [31: 0] write_check_addr; // 用于读写冲突检测
	logic [`WRITE_BUFFER_WIDTH-1: 0] write_check_index;
	logic write_check_ready, write_check_direction;
	logic [3: 0] write_check_wstrb;
	logic [3: 0] write_wstrb;
	logic [31: 0] write_combine_data, write_store_data;
	logic [`WRITE_BUFFER_WIDTH-1: 0] write_wb_tail, write_retire_tail, write_retire_tailp1, write_commit_tail;
	logic [`READ_BUFFER_SIZE-1: 0] wr_buffer_conflict;
	logic [$clog2(TAG_SIZE)-1: 0] write_global_index, fetch_global_index, write_check_global_index;

	logic write_ok;
	logic inst1_retire, inst2_retire;

	// 其他信号
	logic is_read_tail;
	logic read_wb_request, write_wb_request;
	logic read_wb_accept, write_wb_accept;
	logic read_wb_success, write_wb_success;
	logic [31: 0] read_out_data;
	logic on_exception;
	logic [4: 0] out_exccode, read_exccode, write_exccode;
	logic read_use_exc, write_use_exc, use_exc;
	logic read_tlb_exc, write_tlb_exc, tlb_exc;
	logic [$clog2(TAG_SIZE)-1: 0] exc_index, wb_compare_index;
	logic exc_direction, older_than_exc, wb_compare_direction;
	logic next_clear;
	logic read_remain1, write_remain1, write_full, read_full;

	logic direction, directionp1;
	logic [$clog2(TAG_SIZE)-1: 0] current_index, current_indexp1;
	logic [1: 0] index_add_num;

	UncacheBuffer_t [UNCACHE_BUFFER_SIZE-1: 0] uncache_buffer;
	logic [UNCACHE_BUFFER_SIZE-1: 0] uncache_en, uncache_buffer_wr;
	logic read_uncache_tail, read_in_uncache, read_uncache_sending;
	logic [UNCACHE_BUFFER_WIDTH-1: 0] uncache_head, uncache_tail, uncache_tailp1;
	logic uncache_ok, uncache_full;
	logic [UNCACHE_BUFFER_WIDTH: 0] uncache_buffer_count;
	logic [1: 0] uncache_retire_num;

// 全局信号
	assign current_indexp1 = en1 & en2 ? current_index + 1 : current_index;
	assign directionp1 = en1 && en2 && current_index == (TAG_SIZE-1) ? ~direction : direction;
	assign index_add_num[1] = en1 & en2;
	assign index_add_num[0] = en1 ^ en2;
	assign data_clear = clear;
	assign data_abandon_lookup = 1'b0;
	always_ff @(posedge cpu_clk)begin
		next_clear <= clear;
		if(cpu_rst_n == 1'b0 || clear)begin
			current_index <= 0;
			direction <= 0;
		end
		else begin
			current_index <= current_index + (index_add_num & {2{~stall}});
			if(!stall && (current_index == (TAG_SIZE-2) && index_add_num == 2'b10 || current_index == (TAG_SIZE-1) && index_add_num != 2'b00))begin
				direction <= ~direction;
			end
		end
	end

// uncache 访问, 同一时间最多只有一条read指令在buffer中
	assign read_uncache_tail = !clear && !read_in_uncache && !uncache_full && read_uncache[read_tail] && read_en[read_tail] && read_addr_ready[read_tail] && (!write_en[write_retire_tail] || write_en[write_retire_tail] && (write_direction[write_retire_tail] == read_direction[read_tail] && write_index[write_retire_tail] > read_buffer[read_tail].index || write_direction[write_retire_tail] != read_direction[read_tail] && write_index[write_retire_tail] < read_buffer[read_tail].index));
	assign uncache_tailp1 = uncache_tail + 1;
	assign uncache_retire_num[1] = inst1_retire & inst2_retire & write_buffer[write_retire_tail].uncache & write_buffer[write_retire_tailp1].uncache;
	assign uncache_retire_num[0] = (inst1_retire ^ inst2_retire) & write_buffer[write_retire_tail].uncache | (inst1_retire & inst2_retire) & (write_buffer[write_retire_tail].uncache ^ write_buffer[write_retire_tailp1].uncache);
	always_ff @(posedge cpu_clk)begin
		if(cpu_rst_n == 1'b0)begin
			for(int i=0; i<UNCACHE_BUFFER_SIZE; i++)begin
				uncache_buffer[i] <= 0;
			end
			uncache_en <= 0;
			uncache_buffer_wr <= 1'b0;
			uncache_head <= 0;
			uncache_tail <= 0;
			uncache_buffer_count <= UNCACHE_BUFFER_SIZE;
			read_in_uncache <= 1'b0;
			read_uncache_sending <= 1'b0;
		end
		else if(next_clear)begin
			uncache_en <= uncache_en & uncache_buffer_wr;
			read_in_uncache <= 1'b0;
			read_uncache_sending <= 1'b0;
		end
		else begin
			uncache_head <= uncache_head + uncache_ok + (uncache_buffer_count != UNCACHE_BUFFER_SIZE && !uncache_en[uncache_head]);
			uncache_tail <= uncache_tail + uncache_retire_num + read_uncache_tail;
			uncache_buffer_count <= uncache_buffer_count + uncache_ok + (uncache_buffer_count != UNCACHE_BUFFER_SIZE && !uncache_en[uncache_head]) - uncache_retire_num - read_uncache_tail;
			uncache_en <= (uncache_en
						| ({UNCACHE_BUFFER_SIZE{((inst1_retire | inst2_retire) & write_buffer[write_retire_tail].uncache) | read_uncache_tail}} & (1 << uncache_tail))
						| ({UNCACHE_BUFFER_SIZE{inst1_retire & inst2_retire & write_buffer[write_retire_tail].uncache & write_buffer[write_retire_tailp1].uncache}} & (1 << uncache_tailp1)))
						& (~({UNCACHE_BUFFER_SIZE{uncache_ok}} & (1 << uncache_head)));
			uncache_buffer_wr <= (uncache_buffer_wr
						| ({UNCACHE_BUFFER_SIZE{(inst1_retire | inst2_retire) & write_buffer[write_retire_tail].uncache}} & (1 << uncache_tail))
						| ({UNCACHE_BUFFER_SIZE{inst1_retire & inst2_retire & write_buffer[write_retire_tail].uncache & write_buffer[write_retire_tailp1].uncache}} & (1 << uncache_tailp1)))
						& (~({UNCACHE_BUFFER_SIZE{read_uncache_tail & ~clear}} & (1 << uncache_tail)));
			if(read_wb_success)begin
				read_in_uncache <= 1'b0;
			end
			if(uncache_ok && !uncache_wr)begin
				read_uncache_sending <= 1'b0;
			end
			if((inst1_retire || inst2_retire) && write_buffer[write_retire_tail].uncache)begin
				uncache_buffer[uncache_tail].addr <= {write_buffer[write_retire_tail].ptag, write_buffer[write_retire_tail].addr[11: 0]};
				uncache_buffer[uncache_tail].wstrb <= write_buffer[write_retire_tail].wstrb;
				uncache_buffer[uncache_tail].data <= write_buffer[write_retire_tail].data;
			end
			if(inst1_retire && inst2_retire && write_buffer[write_retire_tail].uncache && write_buffer[write_retire_tailp1].uncache)begin
				uncache_buffer[uncache_tailp1].addr <= {write_buffer[write_retire_tailp1].ptag, write_buffer[write_retire_tailp1].addr[11: 0]};
				uncache_buffer[uncache_tailp1].wstrb <= write_buffer[write_retire_tailp1].wstrb;
				uncache_buffer[uncache_tailp1].data <= write_buffer[write_retire_tailp1].data;
			end
			if(read_uncache_tail)begin
				read_in_uncache <= 1'b1;
				read_uncache_sending <= 1'b1;
				uncache_buffer[uncache_tail].addr <= {read_buffer[read_tail].ptag, read_buffer[read_tail].addr[11: 0]};
				uncache_buffer[uncache_tail].wstrb <= read_buffer[read_tail].wstrb;
				uncache_buffer[uncache_tail].queue_index <= read_tail;
			end

		end
	end
	assign uncache_req = uncache_en[uncache_head] && !(next_clear && !uncache_wr);
	assign uncache_wr = uncache_buffer_wr[uncache_head];
	assign uncache_addr = uncache_buffer[uncache_head].addr;
	assign uncache_queue_index = uncache_buffer[uncache_head].queue_index;
	assign uncache_data = uncache_buffer[uncache_head].data;
	assign uncache_wstrb = uncache_buffer[uncache_head].wstrb;
	assign uncache_ok = uncache_req & data_uncache_ok;
	assign uncache_full = uncache_buffer_count <= 4;

// 发给提交总线的信号
	assign mem_end = read_wb_request || write_wb_request;
	assign read_wb_accept = 1'b1;
	assign write_wb_accept = !(read_wb_request && read_wb_accept);
	assign read_wb_request = read_en[read_tail] & read_data_ready[read_tail] & is_read_tail;
	assign write_wb_request = write_buffer[write_wb_tail].wb_ready & write_en[write_wb_tail] & ~write_buffer[write_wb_tail].wait_retire && !next_clear;
	assign read_wb_success = read_wb_request & read_wb_accept;
	assign write_wb_success = write_wb_request & write_wb_accept;
	assign inst1_load_pre = en1 & ~inst1_memop[4];
	assign inst2_load_pre = en2 & ~inst2_memop[4];
	assign inst1_store_pre = en1 & inst1_memop[4];
	assign inst2_store_pre = en2 & inst2_memop[4];
	assign read_add_num[1] = inst1_load_pre & inst2_load_pre;
	assign read_add_num[0] = inst1_load_pre ^ inst2_load_pre;
	assign write_add_num[1] = inst1_store_pre & inst2_store_pre;
	assign write_add_num[0] = inst1_store_pre ^ inst2_store_pre;
	assign dis_mem_stall_req = read_full || write_full || read_remain1 && (inst1_load_pre && inst2_load_pre) || write_remain1 && (inst1_store_pre && inst2_store_pre);

	assign is_read_tail = !write_en[write_wb_tail] || (write_en[write_wb_tail] && (write_direction[write_wb_tail] == read_direction[read_tail] && write_index[write_wb_tail] > read_buffer[read_tail].index || write_direction[write_wb_tail] != read_direction[read_tail] && write_index[write_wb_tail] < read_buffer[read_tail].index));

	DataResolveUtil1 data_resolve_util(read_buffer[read_tail].size, read_buffer[read_tail].is_unsigned, read_buffer[read_tail].lwl, read_buffer[read_tail].lwr, read_buffer[read_tail].addr[1: 0], read_buffer[read_tail].data, read_buffer[read_tail].rt_data, read_out_data);
	MemExcResolveUtilR read_exccode_resolve(read_buffer[read_tail].tlb_refill, read_buffer[read_tail].tlb_invalid, read_buffer[read_tail].lwl | read_buffer[read_tail].lwr, user_mode && read_buffer[read_tail].addr[31], read_buffer[read_tail].exccode, read_buffer[read_tail].size, read_buffer[read_tail].addr[1: 0], read_exccode, read_use_exc, read_tlb_exc);
	MemExcResolveUtilW write_exccode_resolve(write_buffer[write_wb_tail].tlb_refill, write_buffer[write_wb_tail].tlb_invalid, write_buffer[write_wb_tail].tlb_modify, write_buffer[write_wb_tail].swl | write_buffer[write_wb_tail].swr, user_mode && write_buffer[write_wb_tail].addr[31], write_buffer[write_wb_tail].exccode, write_buffer[write_wb_tail].size, write_buffer[write_wb_tail].addr[1: 0], write_exccode, write_use_exc, write_tlb_exc);
	assign out_exccode = read_wb_success ? read_exccode : write_exccode;
	assign use_exc = read_wb_success ? read_use_exc : write_use_exc;
	assign tlb_exc = read_wb_success ? read_tlb_exc : write_tlb_exc;
	assign next_mem_rd = read_wb_success ? read_buffer[read_tail].rd : write_buffer[write_wb_tail].rd;
	assign wb_compare_index = read_wb_success ? read_buffer[read_tail].index : write_index[write_wb_tail];
	assign wb_compare_direction = read_wb_success ? read_direction[read_tail] : write_direction[write_wb_tail];
	assign older_than_exc = wb_compare_direction == exc_direction && wb_compare_index < exc_index || wb_compare_direction != exc_direction && wb_compare_index > exc_index;
	always_ff @(posedge cpu_clk)begin
		if(cpu_rst_n == 1'b0 || clear)begin
			mem_rd <= 0;
			mem_rob_index <= 0;
			mem_data <= 0;
			mem_exccode <= 0;
			mem_addr <= 0;
			on_exception <= 0;
			vaddr_we <= 0;
			entryhi_we <= 0;
			vaddr_rob_index <= 0;
			exc_index <= 0;
			exc_direction <= 0;
		end
		else begin
			mem_rd <= read_wb_success ? read_buffer[read_tail].rd : write_buffer[write_wb_tail].sc ? write_buffer[write_wb_tail].rd : 0;
			mem_rob_index <= read_wb_success ? read_buffer[read_tail].rob_index : write_buffer[write_wb_tail].rob_index;
			mem_data <= read_wb_success ? read_out_data : write_buffer[write_wb_tail].sc;
			mem_exccode <= out_exccode;
			if(mem_end && use_exc && (!on_exception || older_than_exc))begin
				mem_addr <= read_wb_success	? read_buffer[read_tail].addr : write_buffer[write_wb_tail].addr;
				on_exception <= 1'b1;
				vaddr_we <= 1'b1;
				vaddr_rob_index <= read_wb_success ? read_buffer[read_tail].rob_index : write_buffer[write_wb_tail].rob_index;
				entryhi_we <= tlb_exc;
				exc_index <= wb_compare_index;
				exc_direction <= wb_compare_direction;
			end
		end
	end

// read stage1: 放入发射队列
	assign inst1_load = en1 & ~inst1_memop[4] & ~stall;
	assign inst2_load = en2 & ~inst2_memop[4] & ~stall;
	assign inst1_unsigned = ~inst1_memop[4] & ~inst1_memop[3] & inst1_memop[2];
	assign inst2_unsigned = ~inst2_memop[4] & ~inst2_memop[3] & inst2_memop[2];
	assign inst1_memsize = inst1_memop[1: 0];
	assign inst2_memsize = inst2_memop[1: 0];
	assign read_indexp1 = inst1_load & inst2_load ? read_head + 1 : read_head;
	assign wbr_read_valid = ({`READ_BUFFER_SIZE{inst1_load & inst2_store}} & (`READ_BUFFER_SIZE'b1 << read_head)) | wbr_read_next_valid;
	assign wbr_write_mask = {`WRITE_BUFFER_SIZE{write_ok}} & (1 << write_commit_tail);
	always_ff @(posedge cpu_clk)begin
		if(cpu_rst_n == 1'b0 || clear)begin
			for(int i=0; i<`READ_BUFFER_SIZE; i++)begin
				read_buffer[i] <= 0;
			end
			read_head <= 0;
			read_search_tail <= 0;
			read_tail <= 0;
			in_reorder <= 0;
			read_en <= 0;
			read_rs_ready <= 0;
			read_rt_ready <= 0;
			reorderable <= 0;
			read_uncache <= 0;
			read_data_ready <= 0;
			read_direction <= 0;
			read_remain_count <= `READ_BUFFER_SIZE;
			read_remain1 <= 0;
			read_full <= 0;
			read_addr_ready <= 0;
			wbr_en <= 0;
			wbr_read_next_valid <= 0;
			in_reorder_copy <= 0;
		end
		else begin
			read_en <= (read_en 
						| ({`READ_BUFFER_SIZE{inst1_load}} & (1 << read_head))
						| ({`READ_BUFFER_SIZE{inst2_load}} & (1 << read_indexp1)))
						& (~({`READ_BUFFER_SIZE{read_wb_success}} & (1 << read_tail)));
			read_head <= read_head + inst1_load + inst2_load;
			read_tail <= read_tail + read_wb_success;
			read_search_tail <= read_search_tail + (data_addr_ok & read_ready_pre[read_search_tail] & is_search_read_tail) + (read_wb_success & ~read_buffer[read_tail].force_search);
			read_remain_count <= read_remain_count - inst1_load - inst2_load + read_wb_success;
			read_remain1 <= (read_remain_count - inst1_load - inst2_load + read_wb_success) <= 1;
			read_full <= (read_remain_count - inst1_load - inst2_load + read_wb_success) == 0;
			in_reorder <= (in_reorder
						| ({`READ_BUFFER_SIZE{data_addr_ok & ((|read_ready) | (read_ready_pre[read_search_tail] & is_search_read_tail))}} & (1 << read_index)))
						& (~({`READ_BUFFER_SIZE{inst1_load}} & (1<< read_head)))
						& (~({`READ_BUFFER_SIZE{inst2_load}} & (1 << read_indexp1)))
						& (~({`READ_BUFFER_SIZE{wr_stage2_conflict | wr_stage3_conflict}} & (1 << read_index_next)))
						& (~({`READ_BUFFER_SIZE{data_req_out_next & ~data_data_ok & ~enable_miss_next}} & (1 << read_queue_index)))
						& (~wr_buffer_conflict);
			in_reorder_copy <= (in_reorder_copy
						| ({`READ_BUFFER_SIZE{data_addr_ok & ((|read_ready) | (read_ready_pre[read_search_tail] & is_search_read_tail))}} & (1 << read_index)))
						& (~({`READ_BUFFER_SIZE{inst1_load}} & (1<< read_head)))
						& (~({`READ_BUFFER_SIZE{inst2_load}} & (1 << read_indexp1)))
						& (~({`READ_BUFFER_SIZE{wr_stage2_conflict | wr_stage3_conflict}} & (1 << read_index_next)))
						& (~({`READ_BUFFER_SIZE{data_req_out_next & ~data_data_ok & ~enable_miss_next}} & (1 << read_queue_index)))
						& (~wr_buffer_conflict);
			reorderable <= (reorderable
						| ({`READ_BUFFER_SIZE{inst1_load}} & (1 << read_head))
						| ({`READ_BUFFER_SIZE{inst2_load}} & (1 << read_indexp1)))
						& (~wr_buffer_conflict);
			read_data_ready <= (read_data_ready
						| ({`READ_BUFFER_SIZE{data_data_ok & ~wr_stage5_conflict2}} & (1 << read_queue_index))
						| ({`READ_BUFFER_SIZE{req_next_stage & (data_rwstrb_next == 4'b0) & ~wr_stage5_conflict2}} & (1 << req_next_index))
						| ({`READ_BUFFER_SIZE{mshr_data_ok}} & (1 << mshr_queue_index)))
						& (~({`READ_BUFFER_SIZE{inst1_load}} & (1 << read_head)))
						& (~({`READ_BUFFER_SIZE{inst2_load}} & (1 << read_indexp1)))
						& (~wr_buffer_conflict);
			read_uncache <=(read_uncache
						| ({`READ_BUFFER_SIZE{req_next_stage & data_runcache}} & (1 << req_next_index)))
						& (~({`READ_BUFFER_SIZE{inst1_load}} & (1 << read_head)))
						& (~({`READ_BUFFER_SIZE{inst2_load}} & (1 << read_indexp1)));
			wbr_read_next_valid <= ({`READ_BUFFER_SIZE{(inst1_load & ~inst2_store) | inst2_load}} & (1 << read_head))
								| ({`READ_BUFFER_SIZE{inst1_load & inst2_load}} & (1 << read_indexp1));
			for(int i=0; i<`READ_BUFFER_SIZE; i++)begin
				for(int k=0; k<`WRITE_BUFFER_SIZE; k++)begin
					wbr_en[i][k] <= (wbr_en[i][k] | wbr_read_valid[i] & write_en[k]) & ~wbr_write_mask[k];
				end
			end
			if(inst1_load)begin
				read_en[read_head] <= 1'b1;
				read_rs_ready[read_head] <= inst1_rs_ready;
				read_rt_ready[read_head] <= inst1_memop != `MEMOP_LWL && inst1_memop != `MEMOP_LWR || inst1_rt_ready;
				read_addr_ready[read_head] <= 1'b0;
				read_buffer[read_head].is_unsigned <= inst1_unsigned;
				read_buffer[read_head].force_search <= 1'b0;
				read_direction[read_head] <= direction;
				read_buffer[read_head].index <= current_index;
				read_buffer[read_head].rs <= inst1_rs;
				read_buffer[read_head].rt <= inst1_rt;
				read_buffer[read_head].rd <= inst1_rd;
				read_buffer[read_head].rob_index <= rob_index1;
				read_buffer[read_head].offset <= inst1_src2;
				read_buffer[read_head].size <= inst1_memsize;
				read_buffer[read_head].exccode <= inst1_exccode;
				read_buffer[read_head].lwl <= inst1_memop == `MEMOP_LWL;
				read_buffer[read_head].lwr <= inst1_memop == `MEMOP_LWR;
				read_buffer[read_head].tlb_refill <= 1'b0;
				read_buffer[read_head].tlb_invalid <= 1'b0;
			end
			if(inst2_load)begin
				read_en[read_indexp1] <= 1'b1;
				read_rs_ready[read_indexp1] <= inst2_rs_ready;
				read_rt_ready[read_indexp1] <= inst2_memop != `MEMOP_LWL && inst2_memop != `MEMOP_LWR || inst2_rt_ready;
				read_addr_ready[read_indexp1] <= 1'b0;
				read_buffer[read_indexp1].is_unsigned <= inst2_unsigned;
				read_buffer[read_indexp1].force_search <= 1'b0;
				read_direction[read_indexp1] <= directionp1;
				read_buffer[read_indexp1].index <= current_indexp1;
				read_buffer[read_indexp1].rs <= inst2_rs;
				read_buffer[read_indexp1].rt <= inst2_rt;
				read_buffer[read_indexp1].rd <= inst2_rd;
				read_buffer[read_indexp1].rob_index <= rob_index2;
				read_buffer[read_indexp1].offset <= inst2_src2;
				read_buffer[read_indexp1].size <= inst2_memsize;
				read_buffer[read_indexp1].exccode <= inst2_exccode;
				read_buffer[read_indexp1].lwl <= inst2_memop == `MEMOP_LWL;
				read_buffer[read_indexp1].lwr <= inst2_memop == `MEMOP_LWR;
				read_buffer[read_indexp1].tlb_refill <= 1'b0;
				read_buffer[read_indexp1].tlb_invalid <= 1'b0;
			end

			for(int i=0; i<`READ_BUFFER_SIZE; i++)begin
				if(read_en[i])begin
					read_rs_ready[i] <= read_rs_ready[i] || (wb_en1 && read_buffer[i].rs == wb_rd1) || (wb_en2 && read_buffer[i].rs == wb_rd2) || (wb_en3 && read_buffer[i].rs == wb_rd3);
					read_rt_ready[i] <=read_rt_ready[i] || (wb_en1 && read_buffer[i].rt == wb_rd1) || (wb_en2 && read_buffer[i].rt == wb_rd2) || (wb_en3 && read_buffer[i].rt == wb_rd3);
				end
			end

			if(data_data_ok)begin
				read_buffer[read_queue_index].data <= read_combine_data;
			end
			if(req_next_stage && (data_rwstrb_next == 4'b0))begin
				read_buffer[req_next_index].data <= req_combine_data;
			end
			if(mshr_data_ok)begin
				read_buffer[mshr_queue_index].data <= mshr_combine_data;
			end

			if(data_addr_ok & read_ready_pre[read_search_tail] & is_search_read_tail)begin
				read_buffer[read_search_tail].force_search <= 1'b1;
			end
			read_buffer[read_index_next].wstrb <= read_wstrb;
			if(search4_en_next)begin
				read_buffer[read_rt_index].rt_data <= store_data4;
			end
			if(req_next_stage)begin
				read_buffer[req_next_index].ptag <= prtag;
				read_buffer[req_next_index].tlb_invalid <= rdata_tlb_invalid;
				read_buffer[req_next_index].tlb_refill <= rdata_tlb_refill;
			end
			read_buffer[read_index_next].addr <= read_addr;
			if(read_valid)begin
				read_addr_ready[read_index_next] <= 1'b1;
			end
		end
	end

// read stage2 判断是否存在准备完成的指令
	assign read_ready_pre = read_en & read_rs_ready & read_rt_ready & ~in_reorder & ~read_uncache;
	assign read_ready = read_ready_pre & reorderable;
	priority_encoder_multi #(`READ_BUFFER_SIZE) encoder_read_index(read_ready, read_ready_encode);
	assign is_search_read_tail = !write_en[fetch_index] || write_en[fetch_index] && (write_direction[fetch_index] == read_direction[read_search_tail] && write_index[fetch_index] > read_buffer[read_search_tail].index || write_direction[fetch_index] != read_direction[read_search_tail] && write_index[fetch_index] < read_buffer[read_search_tail].index); // 比即将写入store_buffer的写指令还晚
	assign read_index = read_ready_pre[read_search_tail] ? read_search_tail : read_ready_encode;
	assign search3 = read_buffer[read_index].rs;

	always_ff @(posedge cpu_clk)begin
		if(clear)begin
			read_valid <= 1'b0;
		end
		else if(data_addr_ok | wr_stage2_conflict | wr_stage3_conflict | wr_stage4_conflict)begin
			read_valid <= (|read_ready) || is_search_read_tail & read_ready_pre[read_search_tail];
		end
		if(data_addr_ok | wr_stage2_conflict | wr_stage3_conflict | wr_stage4_conflict)begin
			store_data3 <= data3;
			store_offset <= read_buffer[read_index].offset;
			read_index_next <= read_index;
			read_tail_next <= is_search_read_tail & read_ready_pre[read_search_tail];
			read_global_index <= read_buffer[read_index].index;
			read_direction_stage2 <= read_direction[read_index];
		end
	end

// read stage3 计算地址并发送读请求
	assign read_addr = store_data3 + store_offset;
	assign read_addr_offset = store_data3[1: 0] + store_offset[1: 0];
	assign read_wstrb = read_buffer[read_index_next].size == 2'b00 ? (4'b0001 << read_addr_offset) : read_buffer[read_index_next].size == 2'b01 ? (4'b0011) << read_addr_offset : 4'b1111;
	assign wr_stage2_conflict = read_valid && write_check_ready && (write_check_direction == read_direction_stage2 && write_check_global_index < read_global_index || write_check_direction != read_direction_stage2 && write_check_global_index > read_global_index) && read_addr[31: 2] == write_check_addr[31: 2] && ((read_wstrb & write_wstrb) != 4'b0000);
	assign wr_stage3_conflict = read_valid && fetch_ready && writeable && (fetch_direction == read_direction_stage2 && fetch_global_index < read_global_index || fetch_direction != read_direction_stage2 && fetch_global_index > read_global_index) && read_addr[31: 2] == fetch_addr[31: 2] && ((read_wstrb & write_check_wstrb) != 4'b0000);
	assign search4_en = (read_buffer[read_index_next].lwl | read_buffer[read_index_next].lwr) & read_valid;
	assign search4 = read_buffer[read_index_next].rt;
	assign data_req = data_req_before & (data_rwstrb != 4'b0); // data_rwstrb == 0 说明数据全部在store_buffer中，不需要矾根呢缓存
	always_ff @(posedge cpu_clk)begin
		read_rt_index <= read_index_next;
		search4_en_next <= search4_en;
		store_data4 <= data4;
		req_next_stage <= data_req_before;
		req_next_index <= out_queue_index;
		data_rwstrb_next <= data_rwstrb;
		read_valid_next <= read_valid;
		if(cpu_rst_n == 1'b0 || clear)begin
			data_req_before <= 1'b0;
		end
		else if(wr_stage2_conflict | wr_stage3_conflict)begin // 阻止阶段2指令流向阶段3
			data_req_before <= data_req & data_addr_ok ? 1'b0 : data_req; // 如果上一周期指令没有被dcache接受则继续发送请求
		end
		else if((data_addr_ok) | wr_stage4_conflict)begin
			data_req_before <= read_valid;
		end
		if((data_addr_ok) | wr_stage4_conflict)begin
			out_direction <= read_direction_stage2;
			read_global_index_next <= read_global_index;
			enable_miss <= read_tail_next; 
			out_queue_index <= read_index_next;
			data_addr <= read_addr;
			data_rwstrb <= remain_wstrb;
			read_wstrb2 <= read_wstrb;
		end

		if(data_addr_ok || data_req_before && (data_rwstrb == 4'b0))begin
			data_req_next <= data_req_before;
			data_req_out_next <= data_req;
			enable_miss_next <= enable_miss;
			out_direction_next <= out_direction;
			read_global_index3 <= read_global_index_next;
			read_wstrb3 <= read_wstrb2;
			data_addr_next <= data_addr;
		end
		else if(!data_addr_ok)begin
			data_req_next <= 1'b0;
			data_req_out_next <= 1'b0;
		end
	end

	SDPRAM #(
		.WORD_WIDTH(36), 
		.DEPTH(`READ_BUFFER_SIZE),
		.ADDR_WIDTH(`READ_BUFFER_WIDTH)
	) read_snap_buffer(
		.clk(cpu_clk),
		.ena(1'b1),
		.addra(read_rt_index),
		.wea(read_valid_next),
		.dina(({36{wr_combine_en}} & {wr_combine_data, wr_wstrb})),
		.douta(snap_outa),
		.enb(read_data_quick_back),
		.addrb(req_next_index),
		.doutb(snap_outb)
	);

	SDPRAM #(
		.WORD_WIDTH(36), 
		.DEPTH(`READ_BUFFER_SIZE),
		.ADDR_WIDTH(`READ_BUFFER_WIDTH)
	) read_snap_buffer1(
		.clk(cpu_clk),
		.ena(1'b1),
		.addra(read_rt_index),
		.wea(read_valid_next),
		.dina(({36{wr_combine_en}} & {wr_combine_data, wr_wstrb})),
		.douta(snap_outa1),
		.enb(1'b1),
		.addrb(mshr_queue_index),
		.doutb(snap_outb1)
	);
	for(genvar i=0; i<`WRITE_BUFFER_SIZE; i++)begin
		assign read_write_buffer_hit[i] = wbr_en[read_index_next][i] && !write_buffer[i].uncache && (write_buffer[i].addr[31: 2] == read_addr[31: 2]);
		assign read_write_hit_wstrb[i] = {4{read_write_buffer_hit[i]}} & write_buffer[i].wstrb;
	end
	assign read_conflict_wstrb = read_write_hit_wstrb[0] | read_write_hit_wstrb[1] | read_write_hit_wstrb[2] | read_write_hit_wstrb[3]
							| read_write_hit_wstrb[4] | read_write_hit_wstrb[5] | read_write_hit_wstrb[6] | read_write_hit_wstrb[7]
							| read_write_hit_wstrb[8] | read_write_hit_wstrb[9] | read_write_hit_wstrb[10] | read_write_hit_wstrb[11]
							| read_write_hit_wstrb[12] | read_write_hit_wstrb[13] | read_write_hit_wstrb[14] | read_write_hit_wstrb[15];
	assign remain_wstrb = read_wstrb & ~(read_conflict_wstrb);


	for(genvar i=0; i<8; i++)begin
		WriteCombineUtil write_combine_util(write_commit_tail, read_write_buffer_hit[(i<<1)], read_write_buffer_hit[(i<<1)+1], (i<<1), (i<<1)+1, write_buffer[(i<<1)].wstrb, write_buffer[(i<<1)+1].wstrb, write_buffer[(i<<1)].data, write_buffer[(i<<1)+1].data, bwr_combine_en1[i], bwr_combine_index1[i], bwr_combine_wstrb1[i], bwr_combine_data1[i]);
	end

	always_ff @(posedge cpu_clk)begin
		wr_wstrb <= read_conflict_wstrb;
		wr_commit_tail <= write_commit_tail;
		wr_combine_en1 <= bwr_combine_en1;
		wr_combine_index1 <= bwr_combine_index1;
		wr_combine_wstrb1 <= bwr_combine_wstrb1;
		wr_combine_data1 <= bwr_combine_data1;
	end
	for(genvar i=0; i<4; i++)begin
		WriteCombineUtil write_combine_util(wr_commit_tail, wr_combine_en1[(i<<1)], wr_combine_en1[(i<<1)+1], wr_combine_index1[(i<<1)], wr_combine_index1[(i<<1)+1], wr_combine_wstrb1[(i<<1)], wr_combine_wstrb1[(i<<1)+1], wr_combine_data1[(i<<1)], wr_combine_data1[(i<<1)+1], wr_combine_en2[i], wr_combine_index2[i], wr_combine_wstrb2[i], wr_combine_data2[i]);
	end
	WriteCombineUtil write_commit_util3(wr_commit_tail, wr_combine_en2[0], wr_combine_en2[1], wr_combine_index2[0], wr_combine_index2[1], wr_combine_wstrb2[0], wr_combine_wstrb2[1], wr_combine_data2[0], wr_combine_data2[1], wr_combine_en3[0], wr_combine_index3[0], wr_combine_wstrb3[0], wr_combine_data3[0]);
	WriteCombineUtil write_commit_util4(wr_commit_tail, wr_combine_en2[2], wr_combine_en2[3], wr_combine_index2[2], wr_combine_index2[3], wr_combine_wstrb2[2], wr_combine_wstrb2[3], wr_combine_data2[2], wr_combine_data2[3], wr_combine_en3[1], wr_combine_index3[1], wr_combine_wstrb3[1], wr_combine_data3[1]);
	WriteCombineUtil write_combine_util5(wr_commit_tail, wr_combine_en3[0], wr_combine_en3[1], wr_combine_index3[0], wr_combine_index3[1], wr_combine_wstrb3[0], wr_combine_wstrb3[1], wr_combine_data3[0], wr_combine_data3[1], wr_combine_en, wr_combine_index, wr_combine_wstrb, wr_combine_data);


// read stage4 将读取到的数据存入rob中
	assign wr_stage4_conflict = data_req_before && fetch_ready && writeable && (fetch_direction == out_direction && fetch_global_index < read_global_index_next || fetch_direction != out_direction && fetch_global_index > read_global_index_next) && data_addr[31: 2] == fetch_addr[31: 2] && ((read_wstrb2 & write_wstrb) != 4'b0000);
	assign wr_stage5_conflict1 = data_req_next && fetch_ready && writeable && (fetch_direction == out_direction_next && fetch_global_index < read_global_index3 || fetch_direction != out_direction_next && fetch_global_index > read_global_index3) && data_addr_next[31: 2] == fetch_addr[31: 2] && ((read_wstrb3 & write_wstrb) != 4'b0000);
	assign wr_stage5_conflict2 = data_req_next && write_check_ready && (write_check_direction == out_direction_next && write_check_global_index < read_global_index3 || write_check_direction != out_direction_next && write_check_global_index > read_global_index3) && data_addr_next[31: 2] == write_check_addr[31: 2] && ((read_wstrb3 & write_check_wstrb) != 4'b0000);
	assign req_direct = req_next_stage & data_runcache;
	assign read_data_quick_back	= data_data_ok || (req_next_stage && (data_rwstrb_next == 4'b0));
	LoadResolveUtil1 load_resolve_util(snap_outb, data_rdata, read_combine_data);
	LoadResolveUtil1 load_resolve_util1(snap_outb, 0, req_combine_data);
	LoadResolveUtil1 load_resolve_util2(snap_outb1, mshr_data, mshr_combine_data);


// write stage1 将写指令存到buffer中
	assign inst1_store = en1 & inst1_memop[4] & ~stall;
	assign inst2_store = en2 & inst2_memop[4] & ~stall;
	assign write_indexp1 = inst1_store & inst2_store ? write_head + 1 : write_head;
	assign write_retire_tailp1 = write_retire_tail + 1;
	assign next_write_retire_remain_count = write_retire_remain_count - inst1_retire - inst2_retire + write_ok;
	assign next_write_retire_en = (write_retire_en
							| ({`WRITE_BUFFER_SIZE{inst1_retire | inst2_retire}} & (1 << write_retire_tail))
							| ({`WRITE_BUFFER_SIZE{inst1_retire & inst2_retire}} & (1 << write_retire_tailp1)))
							& (~({`WRITE_BUFFER_SIZE{write_ok}} & (1 << write_commit_tail)));
	always_ff @(posedge cpu_clk)begin
		if(cpu_rst_n == 1'b0)begin
			for(int i=0; i<`WRITE_BUFFER_SIZE; i++)begin
				write_buffer[i] <= 0;
				write_index[i] <= i;
			end
			write_en <= 0;
			write_retire_en <= 0;
			write_head <= 0;
			write_search_tail <= 0;
			write_wb_tail <= 0;
			write_retire_tail <= 0;
			write_commit_tail <= 0;
			write_direction <= 0;
			write_remain_count <= `WRITE_BUFFER_SIZE;
			write_retire_remain_count <= `WRITE_BUFFER_SIZE;
			write_remain1 <= 0;
			write_full <= 0;
		end
		else if(next_clear)begin
			write_head <= write_retire_tail;
			write_search_tail <= write_retire_tail;
			write_wb_tail <= write_retire_tail;
			write_remain_count <= next_write_retire_remain_count;
			write_retire_remain_count <= next_write_retire_remain_count;
			write_remain1 <= next_write_retire_remain_count <= 1;
			write_full <= next_write_retire_remain_count == 0;
			write_en <= next_write_retire_en;
			write_retire_en <= next_write_retire_en;
			write_commit_tail <= write_commit_tail + write_ok;
		end
		else begin
			write_head <= write_head + inst1_store + inst2_store;
			write_search_tail <= write_search_tail + ((|write_ready) & writeable);
			write_retire_tail <= write_retire_tail + inst1_retire + inst2_retire;
			write_wb_tail <= write_wb_tail + write_wb_success;
			write_remain_count <= write_remain_count - inst1_store - inst2_store + write_ok;
			write_retire_remain_count <= next_write_retire_remain_count;
			write_remain1 <= (write_remain_count - inst1_store - inst2_store + write_ok) <= 1;
			write_full <= (write_remain_count - inst1_store - inst2_store + write_ok) == 0;
			write_retire_en <= next_write_retire_en;
			write_commit_tail <= write_commit_tail + write_ok;
			if(inst1_store)begin
				write_en[write_head] <= 1'b1;
				write_direction[write_head] <= direction;
				write_index[write_head] <= current_index;
				write_buffer[write_head].wb_ready <= 1'b0;
				write_buffer[write_head].wait_retire <= 1'b0;
				write_buffer[write_head].has_retire <= 1'b0;
				write_buffer[write_head].rs_ready <= inst1_rs_ready;
				write_buffer[write_head].rt_ready <= inst1_rt_ready;
				write_buffer[write_head].exccode <= inst1_exccode;
				write_buffer[write_head].in_store <= 1'b0;
				write_buffer[write_head].addr <= 0;
				// write_buffer[write_head].ready <= 1'b0;
				write_buffer[write_head].rs <= inst1_rs;
				write_buffer[write_head].rt <= inst1_rt;
				write_buffer[write_head].rd <= inst1_rd;
				write_buffer[write_head].rob_index <= rob_index1;
				write_buffer[write_head].offset <= inst1_src2;
				write_buffer[write_head].size <= inst1_memsize;
				write_buffer[write_head].sc <= inst1_memop == `MEMOP_SC;
				write_buffer[write_head].swl <= inst1_memop == `MEMOP_SWL;
				write_buffer[write_head].swr <= inst1_memop == `MEMOP_SWR;
				// write_buffer[write_head].sc <= inst1_memop == `MEMOP_SC;
				// write_buffer[write_head].llbit <= llbit;
				write_buffer[write_head].tlb_invalid <= 1'b0;
				write_buffer[write_head].tlb_refill <= 1'b0;
				write_buffer[write_head].tlb_modify <= 1'b0;
			end
			if(inst2_store)begin
				write_en[write_indexp1] <= 1'b1;
				write_direction[write_indexp1] <= directionp1;
				write_index[write_indexp1] <= current_indexp1;	
				write_buffer[write_indexp1].wb_ready <= 1'b0;
				write_buffer[write_indexp1].wait_retire <= 1'b0;
				write_buffer[write_indexp1].has_retire <= 1'b0;
				write_buffer[write_indexp1].rs_ready <= inst2_rs_ready;
				write_buffer[write_indexp1].rt_ready <= inst2_rt_ready;
				write_buffer[write_indexp1].exccode <= inst2_exccode;
				write_buffer[write_indexp1].in_store <= 1'b0;
				write_buffer[write_indexp1].addr <= 0;
				// write_buffer[write_indexp1].ready <= 1'b0;
				write_buffer[write_indexp1].rs <= inst2_rs;
				write_buffer[write_indexp1].rt <= inst2_rt;
				write_buffer[write_indexp1].rd <= inst2_rd;
				write_buffer[write_indexp1].rob_index <= rob_index2;
				write_buffer[write_indexp1].offset <= inst2_src2;	
				write_buffer[write_indexp1].size <= inst2_memsize;	
				write_buffer[write_indexp1].sc <= inst2_memop == `MEMOP_SC;
				write_buffer[write_indexp1].swl <= inst2_memop == `MEMOP_SWL;
				write_buffer[write_indexp1].swr <= inst2_memop == `MEMOP_SWR;	
				// write_buffer[write_indexp1].sc <= inst2_memop == `MEMOP_SC;
				// write_buffer[write_indexp1].llbit <= inst1_load && inst1_memop == `MEMOP_LL || llbit;
				write_buffer[write_indexp1].tlb_refill <= 1'b0;
				write_buffer[write_indexp1].tlb_invalid <= 1'b0;
				write_buffer[write_indexp1].tlb_modify <= 1'b0;
			end

			for(int i=0; i<`WRITE_BUFFER_SIZE; i++)begin
				if(write_en[i])begin
					write_buffer[i].rs_ready <= write_buffer[i].rs_ready | (wb_en1 && write_buffer[i].rs == wb_rd1) | (wb_en2 && write_buffer[i].rs == wb_rd2) | (wb_en3 && write_buffer[i].rs == wb_rd3);
					write_buffer[i].rt_ready <= write_buffer[i].rt_ready | (wb_en1 && write_buffer[i].rt == wb_rd1) | (wb_en2 && write_buffer[i].rt == wb_rd2) | (wb_en3 && write_buffer[i].rt == wb_rd3);
				end
			end

			if(write_ok)begin
				write_en[write_commit_tail] <= 1'b0;
			end

			if(fetch_ready && writeable)begin
				write_buffer[fetch_index].uncache <= fetch_uncache;
				write_buffer[fetch_index].ptag <= fetch_ptag;
				write_buffer[fetch_index].wstrb <= write_wstrb;
				write_buffer[fetch_index].data <= write_store_data;
				write_buffer[fetch_index].addr <= fetch_addr;
				write_buffer[fetch_index].wb_ready <= 1'b1;
				write_buffer[fetch_index].tlb_invalid <= fetch_tlb_invalid;
				write_buffer[fetch_index].tlb_refill <= fetch_tlb_refill;
				write_buffer[fetch_index].tlb_modify <= fetch_tlb_modify;
			end
			if(write_wb_success)begin
				write_buffer[write_wb_tail].wait_retire <= 1'b1;
			end

			if(inst1_retire || inst2_retire)begin
				write_buffer[write_retire_tail].has_retire <= 1'b1;
			end
			if(inst1_retire && inst2_retire)begin
				write_buffer[write_retire_tailp1].has_retire <= 1'b1;
			end
		end
	end

// write stage2 取数据和地址
	assign write_ready = write_en[write_search_tail] & write_buffer[write_search_tail].rs_ready & write_buffer[write_search_tail].rt_ready & ~write_buffer[write_search_tail].wb_ready;
	assign search1 = write_buffer[write_search_tail].rs;
	assign search2 = write_buffer[write_search_tail].rt;

	always_ff @(posedge cpu_clk)begin
		if(clear)begin
			write_ready_next <= 1'b0;
		end
		else if(writeable)begin
			write_ready_next <= write_ready;
		end
		if(writeable)begin
			write_addr <= write_buffer[write_search_tail].offset + data1;
			write_addr_offset <= write_buffer[write_search_tail].offset[1: 0] + data1[1: 0];
			swl <= write_buffer[write_search_tail].swl;
			swr <= write_buffer[write_search_tail].swr;
			// write_sc <= write_buffer[write_search_tail].sc;
			// write_llbit <= write_buffer[write_search_tail].llbit;
			write_data <= data2;
			write_size <= write_buffer[write_search_tail].size;
			write_search_tail_next <= write_search_tail;
			write_search_direction <= write_direction[write_search_tail];
			write_global_index <= write_index[write_search_tail];
		end
	end

// write stage3 访问tlb
	assign vwtag = write_addr[31: 12];
	always_ff @(posedge cpu_clk)begin
		if(clear)begin
			fetch_ready <= 1'b0;
		end
		else if(writeable)begin
			fetch_ready <= write_ready_next;
		end
		if(writeable)begin
			fetch_addr <= write_addr;
			fetch_offset <= write_addr_offset;
			fetch_swl <= swl;
			fetch_swr <= swr;
			fetch_data <= write_data;
			fetch_size <= write_size;
			fetch_index <= write_search_tail_next;
			// fetch_sc <= write_sc;
			// fetch_llbit <= write_llbit;
			fetch_direction <= write_search_direction;
			fetch_global_index <= write_global_index;
			fetch_ptag <= pwtag;
			fetch_tlb_invalid <= wdata_tlb_invalid;
			fetch_tlb_refill <= wdata_tlb_refill;
			fetch_tlb_modify <= data_tlb_modify;
			fetch_uncache <= data_wuncache;
			write_wstrb <= swl ? 4'b1111 >> (2'b11 - write_addr_offset) : swr ? 4'b1111 << write_addr_offset : write_size == 2'b00 ? (4'b0001 << write_addr_offset) : write_size == 2'b01 ? (4'b0011) << write_addr_offset : 4'b1111;
		end
		write_check_addr <= fetch_addr;
		write_check_index <= fetch_index;
		write_check_direction <= fetch_direction;
		write_check_ready <= fetch_ready & writeable;
		write_check_wstrb <= write_wstrb;
		write_check_global_index <= fetch_global_index;
	end

// write stage4 判断是否是uncache请求， 存入store buffer并清空乱序请求
	assign writeable = ~uncache_full;
	// assign write_wstrb = fetch_swl ? 4'b1111 >> (2'b11 - fetch_offset) : fetch_swr ? 4'b1111 << fetch_offset : fetch_size == 2'b00 ? (4'b0001 << fetch_offset) : fetch_size == 2'b01 ? (4'b0011) << fetch_offset : 4'b1111;

	for(genvar i=0; i<`READ_BUFFER_SIZE; i++)begin
		assign wr_buffer_conflict[i] = read_en[i] && in_reorder_copy[i] && read_addr_ready[i] && fetch_ready && writeable && wbr_en[i][fetch_index] && read_buffer[i].addr[31: 2] == fetch_addr[31: 2] && (|(read_buffer[i].wstrb & write_wstrb)); // 在该条写指令之后的所有读指令
	end

	StoreResolveUtil1 store_resolve2(
		.is_uncache(fetch_uncache),
		.swr(fetch_swr),
		.swl(fetch_swl),
		.uncache_offset(fetch_addr[15: 2]),
		.origin_data(0),
		.input_data(fetch_data),
		.offset(fetch_offset),
		.wstrb(write_wstrb),
		.combine_data(write_store_data)
	);

// write stage5: 写入cache
	assign inst1_retire = retire_en1 && write_en[write_retire_tail] && !write_buffer[write_retire_tail].has_retire && write_buffer[write_retire_tail].rob_index == retire_rob_index1;
	assign inst2_retire = retire_en2 && (write_en[write_retire_tail] && !write_buffer[write_retire_tail].has_retire && (write_buffer[write_retire_tail].rob_index == retire_rob_index2) || write_en[write_retire_tailp1] && !write_buffer[write_retire_tailp1].has_retire && (write_buffer[write_retire_tailp1].rob_index == retire_rob_index2));
	assign data_write_req = write_retire_en[write_commit_tail] & ~write_buffer[write_commit_tail].uncache & ~next_clear;
	assign data_wstrb = write_buffer[write_commit_tail].wstrb;
	assign data_waddr = write_buffer[write_commit_tail].addr;
	assign data_wdata = write_buffer[write_commit_tail].data;
	assign data_write_ptag = write_buffer[write_commit_tail].ptag;
	assign write_ok = (data_write_req & data_waddr_ok) | (write_retire_en[write_commit_tail] & write_buffer[write_commit_tail].uncache);
endmodule

module StoreResolveUtil1(
	input logic is_uncache,
	input logic swl,
	input logic swr,
	input logic [13: 0] uncache_offset,
	input logic [31: 0] origin_data,
	input logic [31: 0] input_data,
	input logic [1: 0] offset,
	input logic [3: 0] wstrb,
	output logic [31: 0] combine_data
);
	logic [31: 0] expand_wstrb;
	logic [31: 0] shift_data;
	logic [4: 0] shift_offset, shift_offset_reverse;
	logic [31: 0] uncache_data;
	logic [31: 0] swrl_data;
	assign swrl_data = swl ? input_data >> shift_offset_reverse : 
						input_data << shift_offset;
	bit_expander_4to32 expander(wstrb, expand_wstrb);
	assign shift_offset = offset << 3;
	assign shift_offset_reverse = (2'b11 ^ offset) << 3;
	assign shift_data = input_data << shift_offset;
	// assign combine_data = swr | swl ? swrl_data : origin_data & (~expand_wstrb) | shift_data & (expand_wstrb);
	assign combine_data = swr | swl ? swrl_data : shift_data;
endmodule

module LoadResolveUtil1(
	input logic [35: 0] origin_data,
	input logic [31: 0] input_data,
	output logic [31: 0] out_data
);
	logic [31: 0] expand_wstrb;
	bit_expander_4to32 expander(origin_data[3: 0], expand_wstrb);
	assign out_data = origin_data[35: 4] & (expand_wstrb) | input_data & (~expand_wstrb);
endmodule

module DataResolveUtil1(
	input logic [1: 0] size,
	input logic unsign_exetand,
	input logic lwl,
	input logic lwr,
	input logic [1: 0] offset,
	input logic [3: 0][7: 0] data,
	input logic [31: 0] rt_data,
	output logic [31: 0] out_data
);
	logic [4: 0] shift_offsetl, shift_offsetr;
	logic [7: 0] byte_data;
	logic [15 :0] half_data;
	logic [31: 0] normal_data, unalign_data, shift_data;
	assign byte_data = data[offset];
	assign half_data = offset[1] == 0 ? {data[1], data[0]} : {data[3], data[2]};
	always_comb begin
		case(size)
		2'b00: begin
			if(unsign_exetand)begin
				normal_data = {24'h000000, byte_data};
			end
			else begin
				normal_data = byte_data[7] == 1'b1 ? {24'hffffff, byte_data} : {24'h000000, byte_data};
			end
			// normal_data = {{24{~unsign_exetand & byte_data[7]}}, byte_data};
		end
		2'b01: begin
			if(unsign_exetand)begin
				normal_data = {16'h0000, half_data};
			end
			else begin
				normal_data = half_data[15] == 1'b1 ? {16'hffff, half_data} : {16'h0000, half_data};
			end
			// normal_data = {{16{~unsign_exetand, byte_data[15]}}, half_data};
		end
		3'b10: begin
			normal_data = data;
		end
		default: normal_data = 0;
		endcase
	end
	logic [31: 0] rt_data_mask;
	always_comb begin
		if(lwr)begin
			case(offset)
			2'b00: rt_data_mask = 32'b0;
			2'b01: rt_data_mask = 32'hff000000;
			2'b10: rt_data_mask = 32'hffff0000;
			2'b11: rt_data_mask = 32'hffffff00;
			endcase
		end
		else begin
			case(offset)
			2'b00: rt_data_mask = 32'h00ffffff;
			2'b01: rt_data_mask = 32'h0000ffff;
			2'b10: rt_data_mask = 32'h000000ff;
			2'b11: rt_data_mask = 32'h00000000;
			endcase
		end
	end
	assign shift_offsetl = (2'b11 ^ offset) << 3; // (3 - offset) * 8
	assign shift_offsetr = offset << 3;
	assign shift_data = lwl ? data << shift_offsetl : data >> shift_offsetr;
	assign unalign_data = shift_data | (rt_data_mask & rt_data);
	assign out_data = lwl | lwr ? unalign_data : normal_data;
endmodule

module MemExcResolveUtilW(
	input logic tlb_refill,
	input logic tlb_invalid,
	input logic tlb_modify,
	input logic _disable,
	input logic user_exc,
	input logic [`EXC_CODE_BUS] origin,
	input logic [1: 0] size,
	input logic [1: 0] offset,
	output logic [`EXC_CODE_BUS] out,
	output logic has_exc,
	output logic has_tlb_exc
);
	logic [1: 0] combine_size;
	assign combine_size = {2{_disable}} | size;
	assign has_exc = tlb_refill || tlb_invalid || tlb_modify || combine_size == 2'b10 && offset != 2'b00 || combine_size == 2'b01 && (offset == 2'b11 || offset == 2'b01) || combine_size == 2'b00 && user_exc;
	assign has_tlb_exc = tlb_refill || tlb_invalid || tlb_modify;
	always_comb begin
		if(origin != `EXC_NONE)begin
			out = origin;
		end
		else if(tlb_refill)begin
			out = `EXC_RTLBS;
		end
		else if(tlb_invalid)begin
			out = `EXC_ITLBS;
		end
		else if(tlb_modify)begin
			out = `EXC_MOD;
		end
		else begin
			out = combine_size == 2'b10 && offset != 2'b00 || combine_size == 2'b01 && (offset == 2'b11 || offset == 2'b01) || combine_size == 2'b00 && user_exc ? `EXC_AdES : `EXC_NONE;
		end
	end
endmodule

module MemExcResolveUtilR(
	input logic tlb_refill,
	input logic tlb_invalid,
	input logic _disable,
	input logic user_exc,
	input logic [`EXC_CODE_BUS] origin,
	input logic [1: 0] size,
	input logic [1: 0] offset,
	output logic [`EXC_CODE_BUS] out,
	output logic has_exc,
	output logic has_tlb_exc
);
	logic [1: 0] combine_size;
	assign combine_size = {2{_disable}} | size;
	assign has_exc = tlb_refill || tlb_invalid || combine_size == 2'b10 && offset != 2'b00 || combine_size == 2'b01 && (offset == 2'b11 || offset == 2'b01) || combine_size == 2'b00 && user_exc;
	assign has_tlb_exc = tlb_refill || tlb_invalid;
	always_comb begin
		if(origin != `EXC_NONE)begin
			out = origin;
		end
		else if(tlb_refill)begin
			out = `EXC_RTLBL;
		end
		else if(tlb_invalid)begin
			out = `EXC_ITLBL;
		end
		else begin
			out = combine_size == 2'b10 && offset != 2'b00 || combine_size == 2'b01 && (offset == 2'b11 || offset == 2'b01) || combine_size == 2'b00 && user_exc ? `EXC_AdEL : `EXC_NONE;
		end
	end
endmodule

module WriteCombineUtil(
	input logic [`WRITE_BUFFER_WIDTH-1: 0] start_index,
	input logic en1,
	input logic en2,
	input logic [`WRITE_BUFFER_WIDTH-1: 0] index1,
	input logic [`WRITE_BUFFER_WIDTH-1: 0] index2,
	input logic [3: 0] wstrb1,
	input logic [3: 0] wstrb2,
	input logic [31: 0] data1,
	input logic [31: 0] data2,
	output logic en,
	output logic [`WRITE_BUFFER_WIDTH-1: 0] index,
	output logic [3: 0] wstrb,
	output logic [31: 0] data
);
	logic compare1, compare2;
	logic [31: 0] expand_wstrb;
	bit_expander_4to32 expander((!compare1 && compare2 ? wstrb1 : wstrb2), expand_wstrb);
	assign compare1 = index1 >= start_index;
	assign compare2 = index2 >= start_index;

	assign en = en1 | en2;
	assign wstrb = ({4{en1}} & wstrb1) | ({4{en2}} & wstrb2);
	always_comb begin
		case({en2, en1})
		2'b00: begin
			data = 0;
			index = index1;
		end
		2'b01: begin
			data = data1;
			index = index1;
		end
		2'b10: begin
			data = data2;
			index = index2;
		end
		2'b11: begin
			data = !compare1 && compare2 ? (data1 & expand_wstrb) | (data2 & ~expand_wstrb) : (data1 & ~expand_wstrb) | (data2 & expand_wstrb);
			index = !compare1 && compare2 ? index1 : index2;
		end
		endcase
	end
endmodule